package dfsketches.gr3d;

public class Camera extends StaticProjector {
	protected CameraAnimation anim;
	protected Vector3D pos;
	protected float angleZ;
	protected float angleX;
	protected float angleY;	
	protected Vector3D directZ;
	protected Vector3D directX;
	protected float zoom;
	protected float w;
	protected float h;

	protected float cachedAngleX;
	protected float cachedAngleY;
	protected float cachedAngleZ;
	protected Matrix3D cachedRotX;
	protected Matrix3D cachedRotY;
	protected Matrix3D cachedRotZ;
	
	private Camera(float width, float height, Matrix3D matrix) {
		super(width, (int)width / 2, (int)height / 2, matrix);
		w = width;
		h = height;
		pos = new Vector3D();
		directX = new Vector3D(1,0,0);
		directZ = new Vector3D(0,0,1);
		zoom = 1f;
		cachedAngleX = 0;
		cachedAngleY = 0;
		cachedAngleZ = 0;
		cachedRotZ = cachedRotX = cachedRotY = Matrix3D.getUniteMatrix();
		updateMatrix();
	}
	
	public Camera(float width, float height) {
		this(width, height, Matrix3D.getUniteMatrix());
	}
	
	public void reanimate() {
		if (anim == null) return;
		m = anim.getTransform();	//TODO repair to pos and angles
	}
	
	public void playAnimation(CameraAnimation camAnim, float speed) {
		anim = camAnim;
		anim.start(speed);
		reanimate();
	}

	public void rotateY(float angle) {
		angleY -= angle;
		updateMatrix();
	}
	
	public void rotateX(float angle) {
		angleX += angle;
		updateMatrix();
	}
	
	public void moveZ(float dist) {
		pos.addScaled(directZ, -dist);
		updateMatrix();
	}
	
	public void moveX(float dist) {
		pos.addScaled(directX, -dist);
		updateMatrix();
	}
	
	public float getZoom() {
		return zoom;
	}
	
	public void setZoom(float zoom) {
		this.zoom = zoom;
		k = w * zoom;
	}

	public void setPosition(Vector3D position) {
		pos = new Vector3D(position);
		updateMatrix();
	}
	
//	@Override
//	public void project(Triangle t) {
//		super.project(t);
//	}
	
	protected void updateMatrix() {
		if (cachedAngleZ != angleZ) {
			cachedAngleZ = angleZ;
			cachedRotZ = Matrix3D.getRotationZMatrix(angleZ);
		}
		if (cachedAngleX != angleX) {
			cachedAngleX = angleX;
			cachedRotX = Matrix3D.getRotationXMatrix(angleX);
		}
		if (cachedAngleY != angleY) {
			cachedAngleY = angleY;
			cachedRotY = Matrix3D.getRotationYMatrix(angleY);
		}
		Matrix3D rot = Matrix3D.getUniteMatrix();
		rot.multiplyRight(cachedRotZ);
		rot.multiplyRight(cachedRotY);
		rot.multiplyRight(cachedRotX);
		
		directZ.setCoordinates(0, 0, 1);
		directZ.apply(Matrix3D.getRotationXMatrix(-angleX));	//TODO: cache it too
		directZ.apply(Matrix3D.getRotationYMatrix(-angleY));
		
		directX.setCoordinates(1, 0, 0);
		directX.apply(Matrix3D.getRotationYMatrix(-angleY));
		
		m.makeTranslation(-pos.x, -pos.y, -pos.z);
		m.multiplyRight(rot);
	}

}